import time
from enum import Enum
import threading
from datetime import datetime, timedelta


class TaskState(Enum):
    PENDING = 0
    RUNNING = 1
    FINISH = 2


class Task(object):
    def __init__(self, name, start_time, action, arg=None, count=1, interval=timedelta(days=1)):
        """

        """
        self.name = name
        self.start_time = start_time
        self.interval = interval
        self.count = count
        self.action = action
        self.arg = arg
        self._state = TaskState.PENDING if self.count > 0 else TaskState.FINISH

    def run(self):
        now = datetime.now()
        if self.start_time <= now:
            self._state = TaskState.RUNNING
            if self.arg is None:
                self.action()
            else:
                self.action(self.arg)
            self._state = TaskState.PENDING
            self.count -= 1
            self.start_time += self.interval

        if self.count <= 0:
            self._state = TaskState.FINISH
        else:
            self._state = TaskState.PENDING
        return self._state

    @staticmethod
    def before(a, b):
        if a.start_time < b.start_time:
            return 1
        elif a.start_time < b.start_time:
            return 0
        else:
            return -1


class TimeLine(object):
    def __init__(self, interval=60):
        self._task_queue = []
        self._interval = interval
        self._exit = False
        self._thread = threading.Thread(target=self._run)
        self._lock = threading.Lock()
        self._running = False

    def interval(self, seconds=60):
        self._lock.acquire(False)
        self._interval = seconds
        self._lock.release()

    def shutdown(self):
        self._lock.acquire(False)
        self._exit = True
        self._lock.release()

    def register(self, task):
        self._lock.acquire(False)
        self._task_queue.append(task)
        self._lock.release()

    def clear(self):
        self._lock.acquire(False)
        self._task_queue = []
        self._lock.release()

    def remove(self, task_name):
        self._lock.acquire(False)
        for task in self._task_queue:
            if task.name == task_name:
                self._task_queue.remove(task)
        self._lock.release()

    def _run(self):

        if self._running:
            print('TIMELINE already running.')
            return

        while not self._exit:
            print('timeline', self._interval, datetime.now().strftime('%H %M %S'))
            self._lock.acquire(False)
            for task in self._task_queue:
                state = task.run()
                if state == TaskState.FINISH:
                    self._task_queue.remove(task)
            self._lock.release()

            time.sleep(self._interval)

    def run(self):
        self._thread.start()


if __name__ == "__main__":
    task1 = Task('xx', datetime.now(), lambda: print('xx'), None, 30, timedelta(seconds=5))
    task2 = Task('xx', datetime.now(), lambda: print('dd'), None, 30, timedelta(seconds=8))
    task3 = Task('xx', datetime.now(), lambda: print('ZZ'), None, 30, timedelta(seconds=8))
    timeline1 = TimeLine(1)
    timeline2 = TimeLine(2)

    timeline1.register(task1)
    timeline1.register(task2)
    timeline1.run()

    time.sleep(20)
    timeline2.run()

    timeline1.register(task3)
    timeline2.register(task2)

    time.sleep(100)
    timeline1.shutdown()
    timeline2.shutdown()


